
#ifndef MY_GREGISTERFUNCTION
#define MY_GREGISTERFUNCTION

#include <vector.h>

//Access a 64-bit key from either a 32-bit or 64-bit application. 
#ifndef KEY_WOW64_64KEY
	#define KEY_WOW64_64KEY 0x0100 
#endif	

//Access a 32-bit key from either a 32-bit or 64-bit application. 
#ifndef KEY_WOW64_32KEY
	#define KEY_WOW64_32KEY 0x0200 
#endif

// Define application constants.
#if defined(_WIN64)
	#define CROSS_ACCESS KEY_WOW64_32KEY
#else
	#define CROSS_ACCESS KEY_WOW64_64KEY
#endif

#include "gCreateRegistryKeyValue.hpp"

wstring gRegisterFunction(BOOL unregisterMode) {

	wstring bodyRegFile;
	vector<wstring> subst;

    typedef struct {
        HKEY hkRoot;
        LPWSTR szName;
        LPCWSTR szValue;
    } KEYDATA;
    
	KEYDATA Keys[] =
    {
        { HKEY_CLASSES_ROOT,  L"%PROGID%", g_idDESC },
        { HKEY_CLASSES_ROOT,  L"%PROGID%\\CLSID", g_idCLSID },        
        { HKEY_CLASSES_ROOT,  L"CLSID\\%CLSID%", g_idDESC },
        { HKEY_CLASSES_ROOT,  L"CLSID\\%CLSID%\\InprocServer32", g_idDLLPATH },
        { HKEY_CLASSES_ROOT,  L"CLSID\\%CLSID%\\ProgID", g_idPROGID },
        { 0 }
    };

/*
Registering in-proc COM servers is very simple, the minimum required is just a few registry keys.  
64-bit objects get registered to HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID 
and 32-bit objects get registered to HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Wow6432Node\CLSID.
http://msdn.microsoft.com/en-us/library/ms682390(VS.85).aspx
*/

	REGSAM rsSamViewFlag = 0; 		

	if (gIsWow64()) {
		
		#if defined _WIN32
			wstring prefix = L"SOFTWARE\\Classes\\Wow6432Node\\";
		#endif
		#if defined _WIN64
			wstring prefix = L"SOFTWARE\\Classes\\";
		#endif
		
		unsigned pos = 2;
		do {
			KEYDATA tmp = Keys[pos];
			if (tmp.hkRoot == NULL) break;	
			tmp.hkRoot = HKEY_LOCAL_MACHINE;	
			wstring current = tmp.szName;
			wstring offset = prefix + current;			
			subst.push_back(offset);
			tmp.szName = const_cast<LPWSTR>(offset.c_str());
			Keys[pos] = tmp;
			pos++;
		} while(TRUE);

		rsSamViewFlag = CROSS_ACCESS;		
		
	};

	if (unregisterMode) {
		KEYDATA tmp = Keys[0];
		Keys[0] = Keys[1];
		Keys[1] = tmp;
		
		tmp = Keys[4];
		Keys[4] = Keys[2];
		Keys[2] = tmp;		
	};
	
	unsigned pos = 0;
	unsigned succ = 0;
	
	do {
	  KEYDATA tmp = Keys[pos];
	  if (tmp.hkRoot == NULL) break;
	  	  
	  wstring keyName = tmp.szName;
	  wstring rootKeyName = L"HKEY_CLASSES_ROOT";
	  if (tmp.hkRoot == HKEY_LOCAL_MACHINE) rootKeyName = L"HKEY_LOCAL_MACHINE";
	  
		map<const wchar_t*, wstring>::const_iterator xpos;
		for(xpos=g_params.begin(); xpos!=g_params.end(); ++xpos) {
			// pos->first: key, post->second: value
			wstring xkey(xpos->first);
			xkey = L"%" + xkey + L"%";
			int indx = keyName.find(xkey.c_str());
			if (indx >= 0) {
				keyName.erase(indx, xkey.length());
				keyName.insert(indx, xpos->second.c_str());
			};

		}
	  
	  wstring keyValue = g_params[tmp.szValue];
	  
	  //MessageBoxW(NULL, keyName.c_str(), keyValue.c_str(), MB_OK);
	  
	  if (unregisterMode) {
	  	DWORD ret = RegDeleteKeyW(tmp.hkRoot, keyName.c_str());
		if (ret == ERROR_SUCCESS) {
			succ++;
		} else {
//			gErrorMsgW(ret, const_cast<PWSTR>(keyName.c_str()), NULL);
			bodyRegFile = bodyRegFile + L"\r\n[-" + rootKeyName + L"\\" + keyName + L"]\r\n";
		}
	  } else {

		REGSAM rsSVF = rsSamViewFlag;
	  	if (tmp.hkRoot == HKEY_CLASSES_ROOT) rsSVF = 0;
	  	
		DWORD ret = gCreateRegistryKeyValue(
			        tmp.hkRoot,
					keyName.c_str(),
					KEY_READ | KEY_WRITE,
					rsSVF,
					keyValue.c_str(),
					keyValue.length()
					);
					
		if (ret == ERROR_SUCCESS) {
			succ++;
		} else {
			bodyRegFile = bodyRegFile + L"\r\n[" + rootKeyName + L"\\" + keyName + L"]\r\n@=\"" + gEscape(keyValue) + L"\"\r\n";
		}
	  }
	  
	  pos++;
	} while(TRUE);

	if (succ == pos) bodyRegFile.clear();
	return bodyRegFile;

}


 #endif
